﻿--Macaroon, a World of Warcraft® user interface addon.
--Copyright© 2008 Connor H. Chenoweth, aka Maul


Macaroon.Buttons = {}

local unitBuffs = { player = {}, target = {}, focus = {} }
local macroIconIndex = {}
local powerColors = {
	["Mana"] = { r = 0.4, g = 0.4, b = 1.00 },
	["Rage"] = { r = 1.00, g = 0.2, b = 0.2 },
	["Focus"] = { r = 1.00, g = 0.50, b = 0.25 },
	["Energy"] = { r = 1.00, g = 1.00, b = 0.00 },
	["Happiness"] = { r = 0.00, g = 1.00, b = 1.00 },
	["Runes"] = { r = 0.50, g = 0.50, b = 0.50 },
	["Runic Power"] = { r = 0.00, g = 0.82, b = 1.00 },
}
local chargeTable = {}

--# /petaggressive
--# /petattack
--# /petautocastoff
--# /petautocaston
--# /petautocasttoggle
--# /petdefensive
--# /petfollow
--# /petpassive
--# /petstay

local petTokenIcons = {
	petattack = { "Interface\\Icons\\Ability_GhoulFrenzy", MACAROON_STRINGS.PETATTACK },
	petfollow = { "Interface\\Icons\\Ability_Tracking", MACAROON_STRINGS.PETFOLLOW },
	petstay = { "Interface\\Icons\\Spell_Nature_TimeStop", MACAROON_STRINGS.PETSTAY },
	petaggressive = { "Interface\\Icons\\Ability_Racial_BloodRage", MACAROON_STRINGS.PETAGGRESSIVE },
	petdefensive = { "Interface\\Icons\\Ability_Defend", MACAROON_STRINGS.PETDEFENSIVE },
	petpassive = { "Interface\\Icons\\Ability_Seal", MACAROON_STRINGS.PETPASSIVE },
}

local alphaTimer, alphaDir, macroDrag, companionDrag, ss, itemCache, cmdSlash, chargeUpdate = 0, 0
local playerEnteredWorld

--local copies of often used globals
local gsub = string.gsub
local match = string.match
local gmatch = string.gmatch
local lower = string.lower
local find = string.find
local floor = math.floor
local ceil = math.ceil
local strlen = _G.strlen
local strsplit = _G.strsplit
local select = _G.select
local tonumber = _G.tonumber

local HasAction = _G.HasAction
local GetTime = _G.GetTime
local UnitAura = _G.UnitAura
local UnitMana = _G.UnitMana
local MouseIsOver = _G.MouseIsOver
local InCombatLockdown = _G.InCombatLockdown
local SecureCmdOptionParse = _G.SecureCmdOptionParse
local QueryCastSequence = _G.QueryCastSequence

local GetNumShapeshiftForms = _G.GetNumShapeshiftForms
local GetShapeshiftFormInfo = _G.GetShapeshiftFormInfo
local GetContainerNumSlots = _G.GetContainerNumSlots
local GetComboPoints = _G.GetComboPoints

local GetCursorInfo = _G.GetCursorInfo

local IsActionInRange = _G.IsActionInRange

local GetNumMacroIcons = _G.GetNumMacroIcons
local GetMacroIconInfo = _G.GetMacroIconInfo

local GetSpellCooldown = _G.GetSpellCooldown
local GetSpellTexture = _G.GetSpellTexture
local GetSpellCount = _G.GetSpellCount
local IsCurrentSpell = _G.IsCurrentSpell
local IsAutoRepeatSpell = _G.IsAutoRepeatSpell
local IsAttackSpell = _G.IsAttackSpell
local IsSpellInRange = _G.IsSpellInRange

local GetInventoryItemLink = _G.GetInventoryItemLink
local GetItemCooldown = _G.GetItemCooldown
local GetItemInfo = _G.GetItemInfo
local GetItemCount = _G.GetItemCount
local GetItemIcon = _G.GetItemIcon
local IsCurrentItem = _G.IsCurrentItem
local IsItemInRange = _G.IsItemInRange

local GetPetActionInfo = _G.GetPetActionInfo
local GetPetActionsUsable = _G.GetPetActionsUsable
local GetPetActionSlotUsable = _G.GetPetActionSlotUsable
local GetPetActionCooldown = _G.GetPetActionCooldown

local GetCompanionCooldown = _G.GetCompanionCooldown

local autoCastStart = AutoCastShine_AutoCastStart
local autoCastStop = AutoCastShine_AutoCastStop

local copyTable = Macaroon.copyTable
local clearTable = Macaroon.clearTable
local spellIndex = Macaroon.spellIndex
local companionIndex = Macaroon.companionIndex
local tooltipScan = MacaroonTooltipScan
local tooltipScanTextLeft2 = MacaroonTooltipScanTextLeft2
local getChildrenAndRegions = Macaroon.getChildrenAndRegions
local MACAROON_STRINGS = MACAROON_STRINGS

local function getPowertypeAmount(self)

	tooltipScan:SetOwner(self, "ANCHOR_NONE")

	local spell = self.macrospell

	spell = lower(spell or "")

	if (spell and spell ~= "") then

		if (spellIndex[spell]) then
			tooltipScan:SetSpell(spellIndex[spell][1], spellIndex[spell][4])
		end
	end

	local amount, powerType, text = nil, nil, tooltipScanTextLeft2:GetText()

	if (text) then
		amount, powerType = match(tooltipScanTextLeft2:GetText(), "(%d+)%s(%a+)")
	end

	if (amount and powerType) then
		return tonumber(amount), powerType
	end
end

local function itemChargeScan(self)

	tooltipScan:SetOwner(self, "ANCHOR_NONE")

	local charges, tooltip = MACAROON_STRINGS.CHARGES, tooltipScan:GetName().."TextLeft"

	clearTable(chargeTable)

	for bag=0,4 do

		for slot=1,GetContainerNumSlots(bag) do

			tooltipScan:SetBagItem(bag, slot)

			local item = tooltipScan:GetItem()

			if (item) then

				local i, text = 1

				repeat

					text = _G[tooltip..i]:GetText()

					if (text and find(text, charges) and not chargeTable[item]) then
						chargeTable[item] = i..";"..bag..";"..slot
					end

					i = i + 1

				until (not text)
			end
		end
	end
end

local function GetItemCharge(self, item)

	local line, bag, slot, text, charges = (";"):split(chargeTable[item])

	tooltipScan:SetOwner(self, "ANCHOR_NONE")
	tooltipScan:SetBagItem(bag, slot)

	text = _G[tooltipScan:GetName().."TextLeft"..line]:GetText()

	if (text) then
		charges = match(text, "%d+")
	end

	return charges or ""
end

local function control_OnUpdate(self, elapsed)

	alphaTimer = alphaTimer + elapsed * 2

	if (alphaDir == 1) then
		if (1-alphaTimer <= 0) then
			alphaDir = 0; alphaTimer = 0
		end
	else
		if (alphaTimer >= 1) then
			alphaDir = 1; alphaTimer = 0
		end
	end

	if (chargeUpdate and self.elapsed > 0.5) then
		itemChargeScan(self); chargeUpdate = nil
	end
end

local onUpdate = MacaroonControl:GetScript("OnUpdate")
MacaroonControl:SetScript("OnUpdate", function(self, elapsed) onUpdate(self, elapsed) control_OnUpdate(self, elapsed) end)

local function updateNonPet(button)

	AutoCastShine_AutoCastStop(button.shine)
	button.autocastsim:Hide()
	button.autocastable:Hide()
	button.autocastenabled = false
end

local function changeButtonType(button)

	if (button.config.type == "macro") then

		button.config.type = "action"
		updateNonPet(button)

	elseif (button.config.type == "action") then

		button.config.type = "pet"

		if (button.config.barPos > 10) then
			while (button.config.barPos > 10) do
				button.config.barPos = button.config.barPos - 10
			end
		end

		button.config.action = tonumber(button.config.barPos)

	elseif (button.config.type == "pet") then

		button.config.type = "macro"
		updateNonPet(button)

	else
		button.config.type = "macro"
		updateNonPet(button)
	end

	Macaroon.SetButtonType(button)
end

local function autoWriteMacro(self, spell, rank)

	local modifier, mod, addrank = " "
	local spellrank = tonumber(match(rank, "%d+")) or 99

	if (spellIndex[lower(spell)] and spellIndex[lower(spell)][2] > spellrank) then
		addrank = true
	end

	if (ss.selfCast) then
		mod = lower(match(ss.selfCast, "^%a+"))
		modifier = modifier.."[target=player,mod:"..mod.."]"
	end

	if (ss.focusCast) then
		mod = lower(match(ss.focusCast, "^%a+"))
		modifier = modifier.."[target=focus,mod:"..mod.."]"
	end

	if (ss.rightClickTarget) then
		mod = ss.rightClickTarget
		modifier = modifier.."[target="..mod..",btn:2]"
	end

	if (self.bar and self.bar.config.target) then
		mod = self.bar.config.target
		modifier = modifier.."[target="..mod.."]"
	end

	if (mod) then
		modifier = modifier.."[] "
	end

	if (not find(rank, "%d+") or IsControlKeyDown() or addrank) then

		spell = spell.."("..rank..")"

	elseif (find(spell, "%(")) then

		spell = spell.."()"
	end

	return "#autowrite\n/cast"..modifier..spell
end

local function updateScale(self, button, delta)

	if (delta > 0) then
		button.config.scale = button.config.scale + 0.01
	else
		button.config.scale = button.config.scale - 0.01
		if (button.config.scale < 0.2) then
			button.config.scale = 0.2
		end
	end

	button.bar.updateBar(button.bar, nil, true, true)
end

local function updateXoffset(self, button, delta)

	if (delta > 0) then
		button.config.XOffset = button.config.XOffset + 0.5
	else
		button.config.XOffset = button.config.XOffset - 0.5
	end

	button.bar.updateBar(button.bar, nil, true, true)
end

local function updateYoffset(self, button, delta)

	if (delta > 0) then
		button.config.YOffset = button.config.YOffset + 0.5
	else
		button.config.YOffset = button.config.YOffset - 0.5
	end

	button.bar.updateBar(button.bar, nil, true, true)
end

local function updateClicks(button)

	if (not button.config.upClicks and not button.config.downClicks) then
		button:RegisterForClicks(ss.registerForClicks)
	elseif (button.config.upClicks and button.config.downClicks) then
		button:RegisterForClicks("AnyDown","AnyUp")
	elseif (button.config.upClicks and not button.config.downClicks) then
		button:RegisterForClicks("AnyUp")
	elseif (not button.config.upClicks and button.config.downClicks) then
		button:RegisterForClicks("AnyDown")
	end
end

local actionTable = {
	[MACAROON_STRINGS.BTNOPTION_EDIT_BUTTON_1] = updateScale,
	[MACAROON_STRINGS.BTNOPTION_EDIT_BUTTON_2] = updateXoffset,
	[MACAROON_STRINGS.BTNOPTION_EDIT_BUTTON_3] = updateYoffset,
}

local function updateValues(self, delta)

	if (actionTable[self.action]) then
		actionTable[self.action](self, self:GetParent(), delta)
	end
end

local function updateButtonData(button, bar, state)

	button.bar = bar
	button.alpha = bar.config.alpha
	button.showGrid = bar.config.showGrid
	button:SetAttribute("showgrid-bar", bar.config.showGrid)

	button.config.showstates = state
	button:SetAttribute("showstates", state)

	button.skincolor = bar.config.visuals.color1
	button.hovercolor = bar.config.visuals.color2
	button.equipcolor = bar.config.visuals.color3
	button.rangecolor = bar.config.visuals.color4
	button.manacolor = bar.config.visuals.color5
	button.buffcolor = bar.config.visuals.color6
	button.debuffcolor = bar.config.visuals.color7
	button.cdcolor1 = bar.config.visuals.color8
	button.cdcolor2 = bar.config.visuals.color9
	button.bdcolor1 = bar.config.visuals.color10
	button.bdcolor2 = bar.config.visuals.color11

	button.hasAction = bar.hasAction
	button.noAction = bar.noAction

	button.config.bar = bar:GetID()
	button.config.stored = false

	button:SetFrameStrata(bar.config.buttonStrata)

	button:SetFrameLevel(4)
	button.iconframe:SetFrameLevel(2)
	button.iconframecooldown:SetFrameLevel(3)
	button.iconframebuffup:SetFrameLevel(3)

	button.hotkey:SetText(match(button.config.hotKeyText, "^:([^:]+)") or "")

	if (bar.handler and not button.config.stored) then
		Macaroon.UpdateButtonVisibility(button, bar.handler:GetAttribute("state-current"))
	end

	Macaroon.EditFrames[button] = button.editframe
end

local function buttonDefaults(index, button)

	button.config = {
		bar = 0,
		barPos = 0,
		showstates = "",
		laststate = "",
		hotKeys = ":",
		hotKeyText = ":",
		hotKeyLock = false,
		stored = true,

		action = index,
		spell = "",

		type = "macro",
		macro = "",
		macroIcon = 1,
		macroName = "",
		macroNote = "",
		macroUseNote = false,
		macroAuto = false,
		macroRand = false,

		mouseAnchor = false,
		clickAnchor = false,
		anchorDelay = false,
		anchoredBar = false,

		scale = 1,
		XOffset = 0,
		YOffset = 0,
		upClicks = false,
		downClicks = false,
		spellCounts = false,
		comboCounts = false,
		target = "none",
	}

	if (button.config.action > Macaroon.maxActionID) then
		while (button.config.action > Macaroon.maxActionID) do
			button.config.action = button.config.action - Macaroon.maxActionID
		end
	end
end

local function createButton(index)

	local button

	if (_G["MacaroonButton"..index]) then
		button = _G["MacaroonButton"..index]
		button.macrospell=nil; button.macroitem=nil; button.macroshow=nil; button.macrorank=nil
	else
		button = CreateFrame("CheckButton", "MacaroonButton"..index, UIParent, "MacaroonButtonTemplate")
	end

	local buttonName, objects = button:GetName(), nil

	button:SetAttribute("showgrid", 0)
	button:SetAttribute("showstates", "homestate")
	button:SetAttribute("hotkeys", "")
	button:SetAttribute("tempid", index)
	button:SetID(0)
	button.id = index
	button.autocasttype = "AutoCast"

	buttonDefaults(index, button)

	objects = getChildrenAndRegions(button)

	for k,v in pairs(objects) do
		local name = gsub(v, button:GetName(), "")
		button[lower(name)] = _G[v]
	end

	button.bindframe:SetID(index)
	button.bindframe.bindType = "button"

	button.leftclick = changeButtonType
	button.updateButtonData = updateButtonData
	button.updateClicks = updateClicks
	button.editframe.updateValues = updateValues

	button.updateClicks(button)

	button:SetAttribute("_childupdate", [[

			local self, message = self, message

			self:SetAttribute("stateshown", false)

			for showstate in gmatch(self:GetAttribute("showstates"), "[^;]+") do
				if (message and strfind(message, showstate)) then

					if (self:GetAttribute("hasaction") or
					    self:GetAttribute("showgrid-bar") or
					    self:GetAttribute("editmode")) then
						self:Show()
					end

					self:SetAttribute("stateshown", true)

					for i=1,select('#',(":"):split(self:GetAttribute("hotkeys"))) do
						self:SetBindingClick(false, select(i,(":"):split(self:GetAttribute("hotkeys"))), self:GetName())
					end

				end
			end

			if (not self:GetAttribute("stateshown")) then
				self:Hide()
				for key in gmatch(self:GetAttribute("hotkeys"), "[^:]+") do
					self:ClearBinding(key)
				end
			end
		]] )

	SecureHandler_OnLoad(button)

	if (not ss.buttons) then
		ss.buttons = {}
	end

	ss.buttons[index] = { button.config }

	Macaroon.Buttons[index] = { button, 1 }

	updateButtonData(button, MacaroonButtonStorage)

	Macaroon.SetButtonType(button)

	return button
end

--[[ Button Update Functions ]]--

local function updateCooldownText(button, start, duration, enable)

	if (not button.cooldowntext1) then
		return
	end

	if ( start > 0 and duration > 4 and enable > 0) then

		local coolDown = ceil(duration-(GetTime()-start))
		local formatted = coolDown

		if (coolDown < 6) then
			button.cooldowntext1:Hide()
			button.cooldowntext2:Show()
		else
			button.cooldowntext1:Show()
			button.cooldowntext2:Hide()
		end

		if (coolDown >= 60) then
			formatted = ceil(coolDown/60)
			formatted = formatted.."m";
		end

		if (coolDown >= 3600) then
			formatted = ceil(coolDown/3600)
			formatted = formatted.."h";
		end

		if (coolDown >= 86400) then
			formatted = ceil(coolDown/86400)
			formatted = formatted.."d";
		end

		button.cooldowntext2:SetText(formatted)
		button.cooldowntext1:SetText(formatted)
	else
		button.cooldowntext1:SetText("")
		button.cooldowntext2:SetText("")
	end
end

local function updateBuffInfo(unit)

	local index, spell, rank, _, duration, timeLeft, isMine = 1

	clearTable(unitBuffs[unit])

	repeat
		spell, rank, _, _, _, duration, timeLeft, isMine = UnitAura(unit, index, "HELPFUL")

		if (duration and isMine) then
			unitBuffs[unit][spell] = "buff"..":"..duration..":"..timeLeft
			unitBuffs[unit][spell.."()"] = "buff"..":"..duration..":"..timeLeft
			unitBuffs[unit][spell.."("..rank..")"] = "buff"..":"..duration..":"..timeLeft
		end

		index = index + 1

   	until (not spell)

	index = 1

	repeat

		spell, rank, _, _, _, duration, timeLeft, isMine = UnitAura(unit, index, "HARMFUL")

		if (duration and isMine) then
			unitBuffs[unit][spell] = "debuff"..":"..duration..":"..timeLeft
			unitBuffs[unit][spell.."()"] = "debuff"..":"..duration..":"..timeLeft
			unitBuffs[unit][spell.."("..rank..")"] = "debuff"..":"..duration..":"..timeLeft
		end

		index = index + 1

	until (not spell)
end

local function updateBuffup_OnEvent(self, unit, spell)

	if (unitBuffs[unit][spell]) then

		local auraType, duration, timeLeft = (":"):split(unitBuffs[unit][spell])

		if (auraType == "buff") then

			if (ss.checkButtons[115] and self.buffcolor) then

				self.border:SetVertexColor(self.buffcolor[1], self.buffcolor[2], self.buffcolor[3], 1.0)
				self.buffup = true
				self.border:Show()
			else
				self.border:SetVertexColor(0.0, 0.0, 0.0, 0.0)
			end

			if (ss.checkButtons[114]) then

				self.buffup = true

				if (self.cdduration < 5) then

					duration = tonumber(duration); timeLeft = tonumber(timeLeft)

					if (duration and timeLeft > 4) then

						if (self.bdcolor1) then
							self.cooldowntext1:SetTextColor(self.bdcolor1[1], self.bdcolor1[2], self.bdcolor1[3])
							self.cooldowntext2:SetTextColor(self.bdcolor2[1], self.bdcolor2[2], self.bdcolor2[3])
						end

						CooldownFrame_SetTimer(self.iconframebuffup, timeLeft-duration, duration, 1)

						self.buffup_duration = duration
						self.buffup_timeLeft = timeLeft
					end

					self.border:Show()
				end
			else
				CooldownFrame_SetTimer(self.iconframebuffup, 0, 0, 0)
			end

		elseif (auraType == "debuff" and unit == "target") then

			if (ss.checkButtons[115]) then
				self.border:SetVertexColor(self.debuffcolor[1], self.debuffcolor[2], self.debuffcolor[3], 1.0)
				self.buffup = true
				self.border:Show()
			else
				self.border:SetVertexColor(0.0, 0.0, 0.0, 0.0)
			end

			if (ss.checkButtons[114]) then

				self.buffup = true

				if (self.cdduration < 2) then

					duration = tonumber(duration); timeLeft = tonumber(timeLeft)

					if (duration and timeLeft > 4) then

						if (self.bdcolor1) then
							self.cooldowntext1:SetTextColor(self.bdcolor2[1], self.bdcolor2[2], self.bdcolor2[3])
							self.cooldowntext2:SetTextColor(self.bdcolor2[1], self.bdcolor2[2], self.bdcolor2[3])
						end

						CooldownFrame_SetTimer(self.iconframebuffup, timeLeft-duration, duration, 1)

						self.buffup_duration = duration
						self.buffup_timeLeft = timeLeft
					end
				end

				self.buffup = true
				self.border:Show()
			else
				CooldownFrame_SetTimer(self.iconframebuffup, 0, 0, 0)
			end
		end

		self.buffupunit = unit

	elseif (self.buffupunit == unit) then

		CooldownFrame_SetTimer(self.iconframebuffup, 0, 0, 0)

		if (ss.checkButtons[114]) then
			updateCooldownText(self, 0, 0, 0)
		end

		self.border:Hide()

		self.buffup = nil
		self.buffupunit = nil
	end
end

local function updateBuffup_OnUpdate(self, unit, spell)

	if (ss.checkButtons[114]) then

		updateBuffInfo(unit)

		if (unitBuffs[unit][spell]) then

			local _, duration, timeLeft = (":"):split(unitBuffs[unit][spell])

			duration = tonumber(duration); timeLeft = tonumber(timeLeft)

			if (duration) then
				updateCooldownText(self, timeLeft-duration or 0, duration or 0, timeLeft or 0)
			else
				updateCooldownText(self, 0, 0, 0)
			end
		else
			updateCooldownText(self, 0, 0, 0)
		end

	elseif (not self.cooldown) then
		updateCooldownText(self, 0, 0, 0)
	elseif (not ss.checkButtons[113]) then
		updateCooldownText(self, 0, 0, 0)
	end
end

local function hasAction(button ,data)

	if (button.config.type == "action") then


		if (HasAction(data)) then
			if (not InCombatLockdown() and data < 121) then
				button:SetAttribute("hasaction", true)
			end
			return true
		else
			if (not InCombatLockdown() and data < 121) then
				button:SetAttribute("hasaction", false)
			end
			return false
		end


	elseif (button.config.type == "macro") then

		if (data and strlen(data) > 0) then
			if (not InCombatLockdown()) then
				button:SetAttribute("hasaction", true)
			end
			return true
		else
			if (not InCombatLockdown()) then
				button:SetAttribute("hasaction", false)
			end
			return false
		end

	elseif (button.config.type == "pet") then

		local _, _, texture = GetPetActionInfo(data)

		if (GetPetActionSlotUsable(data)) then
			if (not InCombatLockdown()) then
				button:SetAttribute("hasaction", true)
			end

			if (texture) then
				return true
			else
				return false
			end
		else
			if (not InCombatLockdown()) then
				button:SetAttribute("hasaction", true)
			end
			return false
		end
	end
end

local function isActiveShapeshiftSpell(spell)

	local shapeshift, texture, name, isActive = match(spell, "^[^(]+")

	for i=1, GetNumShapeshiftForms() do
		texture, name, isActive = GetShapeshiftFormInfo(i)
		if (isActive and lower(name) == lower(shapeshift)) then
			return texture
		end
	end
end

--[[ "action" button functions ]]--

local function updateActionButton(self, action)

	local isUsable, notEnoughMana = IsUsableAction(action)

	if (self.editmode) then

		self.iconframeicon:SetVertexColor(0.2, 0.2, 0.2)

	elseif (isUsable) then

		if (IsActionInRange(action, self.target) == 0) then
			if (self.rangecolor) then
				self.iconframeicon:SetVertexColor(self.rangecolor[1], self.rangecolor[2], self.rangecolor[3])
			else
				self.iconframeicon:SetVertexColor(0.15, 0.7, 0.15)
			end
		else
			self.iconframeicon:SetVertexColor(1.0, 1.0, 1.0)
		end

	elseif (notEnoughMana) then

		if (self.manacolor) then
			self.iconframeicon:SetVertexColor(self.manacolor[1], self.manacolor[2], self.manacolor[3])
		else
			self.iconframeicon:SetVertexColor(0.2, 0.3, 0.0)
		end
	else
		self.iconframeicon:SetVertexColor(0.4, 0.4, 0.4)
	end
end

local function updateActionIcon(self, hasAction, action)

	self.name:SetText(GetActionText(action))

	if (hasAction) then
		self.iconframeicon:SetTexture(GetActionTexture(action))
		self.iconframeicon:Show()
	else
		self.iconframeicon:Hide()
	end
end

local function updateActionState(self, action)

	if ( GetActionCount(action) and GetActionCount(action) > 1) then
		self.count:SetText(GetActionCount(action))
		self.count:SetTextColor(1,1,1)
	else
		self.count:SetText("")
	end

	if (IsCurrentAction(action) or IsAutoRepeatAction(action)) then
		self:SetChecked(1)
	else
		self:SetChecked(nil)
	end

	if ( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) ) then
		self.mac_flash = true
	else
		self.mac_flash = false
	end
end

local function updateAction_OnEvent(self, action)

	tooltipScan:SetOwner(self, "ANCHOR_NONE")
	tooltipScan:SetAction(action)

	local spell = tooltipScan:GetSpell()

	if (spell) then
		self.config.spell = spell
	else
		self.config.spell = ""
	end

	if ( IsEquippedAction(action) ) then

		self.border:SetVertexColor(0, 1.0, 0, 0.5)
		self.border:Show()

	elseif (not self.buffup) then

		self.border:Hide()
	end

	if (hasAction(self, action)) then

		if (self.hasAction) then
			self.normaltexture:SetTexture(self.hasAction)
		end

		self.normaltexture:SetVertexColor(1,1,1,1)

		updateActionIcon(self, true, action)
	else

		self.normaltexture:SetVertexColor(1,1,1,0.35)

		if (self.noAction) then
			self.normaltexture:SetTexture(self.noAction)
		end

		updateActionIcon(self, false, action)
	end

	updateActionState(self, action)
	updateBuffup_OnEvent(self, "player", self.config.spell)
	updateBuffup_OnEvent(self, "target", self.config.spell)
end

local function updateActionCooldown_OnEvent(self, update, action)

	self.cdduration = 0

	if (hasAction(self, action)) then

		local start, duration, enable = GetActionCooldown(action)

		if (enable) then

			if (self.cdcolor1 and duration > 4) then
				self.cooldowntext1:SetTextColor(self.cdcolor1[1], self.cdcolor1[2], self.cdcolor1[3])
				self.cooldowntext2:SetTextColor(self.cdcolor2[1], self.cdcolor2[2], self.cdcolor2[3])
			end

			if ( start > 0 and duration > 0 and enable > 0) then
				CooldownFrame_SetTimer(self.iconframecooldown, start, duration, enable)
				self.cooldown = true;
				self.cdduration = duration
			else
				CooldownFrame_SetTimer(self.iconframecooldown, 0, 0, 0)
				self.cooldowntext1:SetText("")
				self.cooldowntext2:SetText("")
			end
		end

	elseif (update) then

		CooldownFrame_SetTimer(self.iconframecooldown, 0, 0, 0)
		self.cooldowntext1:SetText("")
		self.cooldowntext2:SetText("")
	end
end

local function updateActionCooldown_OnUpdate(self, action)

	local start, duration, enable = GetActionCooldown(action)

	if (start == 0) then
		self.cooldown = nil
	end

	if (self.alpha and duration) then
		if (self.cooldown and duration > 4) then
			if (self:GetAlpha() ~= ss.cooldownAlpha) then
				self:SetAlpha(ss.cooldownAlpha)
			end
		else
			if (self:GetAlpha() ~= 1) then
				self:SetAlpha(1)
			end
		end
	end

	if (ss.checkButtons[113]) then
		updateCooldownText(self, start or 0, duration or 0, enable or 0)
	end
end

local function actionButton_SetTooltip(self)

	local action = self.config.action

	self.UpdateTooltip = nil

	if (action and action ~= "") then
		GameTooltip:SetAction(action)
		self.UpdateTooltip = actionButton_SetTooltip
	end
end

local function actionButton_OnUpdate(self, elapsed)

	self.elapsed = self.elapsed + elapsed

	if (self.mac_flash) then

		self.mac_flashing = true

		if (alphaDir == 1) then
			if ((1-(alphaTimer)) >= 0) then
				self.checkedtexture:SetVertexColor(1, 1, 1, 1)
			end
		elseif (alphaDir == 0) then
			if ((alphaTimer) <= 1) then
				self.checkedtexture:SetVertexColor(0.8, 0, 0, 1)
			end
		end

	elseif (self.mac_flashing) then

		self.checkedtexture:SetVertexColor(1, 1, 1, 1)
		self.mac_flashing = false
	end

	if (self.elapsed > 0.2) then

		updateActionButton(self, self.config.action)

		if (self.cooldown) then
			updateActionCooldown_OnUpdate(self, self.config.action)
		end

		if (self.buffup and self.buffupunit) then
			updateBuffup_OnUpdate(self, self.buffupunit, self.config.spell)
		end

		self.elapsed = 0;
	end
end

local function actionButton_ShowGrid(button)

	if (not InCombatLockdown()) then

		if (button:GetAttribute("stateshown")) then
			button:Show()
		end
	end
end

local function actionButton_HideGrid(button)

	if (not InCombatLockdown()) then

		if (not button.config.stored and not button:GetAttribute("editmode")) then
			if (not MouseIsOver(button) and not hasAction(button ,button.config.action) and not button.showGrid) then
				button:Hide()
			end
		end
	end
end

local function actionButton_OnEvent(self, event, ...)

	if (event == "UPDATE_BONUS_ACTIONBAR") then

		if (self.config.action > 120) then
			hasAction(self, self.config.action)
		end

	elseif (event == "ACTIONBAR_SLOT_CHANGED") then

		local action = self.config.action

		if (select(1,...) ==  0 or select(1,...) ==  action) then
			updateAction_OnEvent(self, action)
			updateActionCooldown_OnEvent(self, true, action)
		end

	elseif (event == "ACTIONBAR_UPDATE_COOLDOWN") then

		updateActionCooldown_OnEvent(self, true, self.config.action)

	elseif ( event == "ACTIONBAR_UPDATE_STATE" or event == "CRAFT_SHOW" or event == "CRAFT_CLOSE" or event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" ) then

		updateActionState(self, self.config.action)

	elseif (event == "ACTIONBAR_SHOWGRID") then

		if (not chargeUpdate) then
			actionButton_ShowGrid(self); self.hidegrid = true
		end

	elseif (event == "ACTIONBAR_HIDEGRID") then

		if (not chargeUpdate or self.hidegrid) then
			actionButton_HideGrid(self); self.hidegrid = nil
		end

	elseif (event == "UNIT_INVENTORY_CHANGED") then

		if (select(1,...) ==  "player") then
			local action = self.config.action
			local hasAction = hasAction(self, action)

			updateActionIcon(self, hasAction, action)
		end

	elseif (event == "UPDATE_SHAPESHIFT_FORM") then

		local action = self.config.action
		local hasAction = hasAction(self, action)

		updateActionState(self, action)
		updateActionIcon(self, hasAction, action)

	elseif (event == "UNIT_AURA") then

		if (select(1,...) ==  "player" or select(1,...) ==  "target") then
			updateActionState(self, self.config.action)
			updateBuffup_OnEvent(self, ..., self.config.spell)
		end

	elseif (self.config.spellCounts and unit == "player" and (event == "UNIT_MANA" or event == "UNIT_RAGE" or event == "UNIT_ENERGY" or event == "UNIT_RUNIC_POWER")) then

		local action = self.config.action
		updateActionState(self, action)

	elseif (event == "PLAYER_TARGET_CHANGED") then

		updateBuffup_OnEvent(self, "target", self.config.spell)

	elseif (event == "PLAYER_ENTERING_WORLD") then

		local action = self.config.action

		updateAction_OnEvent(self, action)
		updateActionCooldown_OnEvent(self, nil, action)
		updateActionState(self, action)

	elseif ( event == "PLAYER_ENTER_COMBAT" or event == "PLAYER_LEAVE_COMBAT") then

		local action = self.config.action
		if (IsAttackAction(action)) then
			updateActionState(self, action)
		end

	elseif ( event == "START_AUTOREPEAT_SPELL" ) then

		local action = self.config.action
		if (IsAutoRepeatAction(action)) then
			updateActionState(self, action)
		end

	elseif ( event == "STOP_AUTOREPEAT_SPELL" ) then

		local action = self.config.action
		if (self.mac_flashing and not IsAttackAction(action)) then
			updateActionState(self, action)
		end
	end
end

--[[ "pet" button functions ]]--

local function updatePetButton(button, action)

	if (button.editmode) then

		button.iconframeicon:SetVertexColor(0.2, 0.2, 0.2)

	elseif (GetPetActionSlotUsable(action)) then

		button.iconframeicon:SetVertexColor(1.0, 1.0, 1.0)
	else
		button.iconframeicon:SetVertexColor(0.4, 0.4, 0.4)
	end
end

local function updatePetIcon(button, name, subtext, texture, isToken)

	button.isToken = isToken

	button.name:SetText("")
	button.count:SetText("")

	if (texture) then

		if (isToken) then
			button.iconframeicon:SetTexture(_G[texture])
			button.tooltipName = _G[name]
		else
			button.iconframeicon:SetTexture(texture)
			button.tooltipName = name
		end

		button.tooltipSubtext = subtext

		button.iconframeicon:Show()

	else
		button.iconframeicon:SetTexture("")
		button.iconframeicon:Hide()
	end
end

local function updatePetState(button, isActive, allowed, enabled)

	if (isActive) then
		button:SetChecked(1)
	else
		button:SetChecked(nil)
	end

	button.shine:SetAlpha(ss.autocastAlpha)

	if (allowed) then
		button.autocastable:Show()
	else
		button.autocastable:Hide()
	end

	if (enabled) then

		if (button.autocasttype == "AutoCast") then

			autoCastStart(button.shine)
			button.autocastsim:Hide()
			button.autocastable:Hide()

		else

			button.autocastsim:Show()
			autoCastStop(button.shine)
			button.autocastable:Hide()

		end

		button.autocastenabled = true
	else
		autoCastStop(button.shine)
		button.autocastsim:Hide()

		if (allowed) then
			button.autocastable:Show()
		end

		button.autocastenabled = false
	end
end

local function updatePet_OnEvent(button)

	local action = button.config.action

	tooltipScan:SetOwner(button, "ANCHOR_NONE")
	tooltipScan:SetPetAction(action)

	local spell = tooltipScan:GetSpell()

	tooltipScan:ClearLines()

	if (spell) then
		button.config.spell = spell
	end

	local name, subtext, texture, isToken, isActive, allowed, enabled = GetPetActionInfo(action)

	if (hasAction(button, action)) then

		if (button.hasAction) then
			button.normaltexture:SetTexture(button.hasAction)
		end

		button.normaltexture:SetVertexColor(1,1,1,1)

	else

		if (button.noAction) then
			button.normaltexture:SetTexture(button.noAction)
		end

		button.normaltexture:SetVertexColor(1,1,1,0.35)
	end

	updatePetIcon(button, name, subtext, texture, isToken)
	updatePetState(button, isActive, allowed, enabled)

end

local function updatePetCooldown_OnEvent(self, action)

	local start, duration, enable = GetPetActionCooldown(action)

	CooldownFrame_SetTimer(self.iconframecooldown, start, duration, enable)

	self.cooldown = true
end

local function updatePetCooldown_OnUpdate(self, action)

	local start, duration, enable = GetPetActionCooldown(action)

	if (start == 0) then
		self.cooldown = nil
	end

	if (self:GetParent().alpha) then
		if (self.cooldown and duration > 4) then
			self:SetAlpha(ss.cooldownAlpha)
		else
			self:SetAlpha(1)
		end
	end

	if (ss.checkButtons[113]) then
		updateCooldownText(self, start or 0, duration or 0, enable or 0)
	end
end

local function petButton_SetTooltip(self)

	local action = self.config.action

	if (self.isToken or not self.UberTooltips) then

		if (self.tooltipName) then
			GameTooltip:SetText(self.tooltipName, 1.0, 1.0, 1.0)

		end

		if ( self.tooltipSubtext ) then
			GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5)
		end
	else

		GameTooltip:SetPetAction(action)
	end

	GameTooltip:Show()
	self.UpdateTooltip = petButton_SetTooltip
end

local function petButton_OnUpdate(self, elapsed)

	self.elapsed = self.elapsed + elapsed

	if (self.autocastenabled and self.autocasttype== "AutoCastSim") then

		if (alphaDir == 1) then
			if ((ss.autocastAlpha-(alphaTimer)) >= 0) then
				self.autocastsim:SetAlpha(ss.autocastAlpha-(alphaTimer))
			end
		else
			if ((alphaTimer) <= ss.autocastAlpha) then
				self.autocastsim:SetAlpha((alphaTimer))
			end
		end
	end

	if (self.elapsed > 0.2) then

		updatePetButton(self, self.config.action)

		if (self.cooldown) then
			updatePetCooldown_OnUpdate(self, self.config.action)
		end

		self.elapsed = 0
	end

end

local function petButton_ShowGrid(button)

	if (not InCombatLockdown()) then

		if (button:GetAttribute("stateshown")) then
			button:Show()
		end
	end
end

local function petButton_HideGrid(button)

	if (not InCombatLockdown()) then

		if (not button.config.stored and not button:GetAttribute("editmode")) then
			if (not MouseIsOver(button) and not hasAction(button, button.config.action) and not button.showGrid) then
				button:Hide()
			end
		end
	end
end

local function petButton_OnEvent(self, event, ...)

	if (event == "PET_BAR_UPDATE" or
	    event == "PLAYER_CONTROL_LOST" or
	    event == "PLAYER_CONTROL_GAINED" or
	    event == "PLAYER_FARSIGHT_FOCUS_CHANGED" or
	    (event == "UNIT_PET" and select(1,...) ==  "player")) then

		updatePet_OnEvent(self)

	elseif (event == "UNIT_FLAGS" or event == "UNIT_AURA") then

		if (select(1,...) ==  "pet") then
			updatePet_OnEvent(self)
		end

	elseif (event =="PET_BAR_UPDATE_COOLDOWN") then

		updatePetCooldown_OnEvent(self, self.config.action)

	elseif (event =="PET_BAR_SHOWGRID") then

		petButton_ShowGrid(self)

	elseif (event =="PET_BAR_HIDEGRID") then

		petButton_HideGrid(self)

	elseif (event == "PLAYER_ENTERING_WORLD") then

		updatePet_OnEvent(self)
		updatePetCooldown_OnEvent(self, self.config.action)
	end
end

--[[ "macro" button functions ]]--

local function setupMacroData(self)

	if (self.macroparse) then

		self.macropet = nil

		--self.lastpass = self.macrospell or self.macroitem or self.macroshow

		local _, spell, item, show, target, command

		for cmd, options in gmatch(self.macroparse, "(%c%p%a+)(%C+)") do

			--after gmatch, remove unneeded characters
			if (cmd) then cmd = gsub(cmd, "^%c+", "") end
			if (options) then options = gsub(options, "^%s+", "") end

			if (find(cmd, "#show")) then
				show = SecureCmdOptionParse(options)
			end

			if (find(cmd, "/pet")) then
				self.macropet = match(cmd, "%a+")
			end

			--find #show option!
			if (not show and find(cmd, "^#show")) then
				show = SecureCmdOptionParse(options)
			--sometimes SecureCmdOptionParse will return "" since that is not what we want, keep looking
			elseif (spell and #spell < 1) then
				show = SecureCmdOptionParse(options)
			end

			--find the spell!
			if (not spell and cmdSlash[cmd]) then
				spell, target = SecureCmdOptionParse(options)
				command = cmd
			elseif (spell and #spell < 1) then
				spell, target = SecureCmdOptionParse(options)
				command = cmd
			end
   		end

   		if (find(self.macroparse, "/.+random")) then

   			self.castrandom = spell

   		else

   			self.castrandom = nil

     			if (spell and command == "/castsequence") then
     				_, item, spell = QueryCastSequence(spell)
     			elseif (spell) then
     			     	if (#spell < 1) then
     					spell = nil
     				elseif(GetItemInfo(spell) or itemCache[spell]) then
     					item = spell; spell = nil
     				elseif(tonumber(spell) and GetInventoryItemLink("player", spell)) then
     					item = GetInventoryItemLink("player", spell); spell = nil
     				end
     			end

     			self.target = target or "target"

			if (spell) then
				self.macroitem = nil
				if (spell ~= self.macrospell) then
					spell = gsub(spell, "!", "")
					self.macrospell = spell
					if (spellIndex[lower(spell)]) then
						self.macrorank = spellIndex[lower(spell)][2]
					else
						self.macrorank = nil
					end
				end
			else
				self.macrospell = nil
				self.macrorank = nil
			end

			if (item) then
				self.macrospell = nil
				self.macrorank = nil
				if (item ~= self.macroitem) then
					self.macroitem = item
				end
			else
				self.macroitem = nil
			end

			if (show) then
				self.macroshow = nil
				if (show ~= self.macroshow) then
     					if(tonumber(show) and GetInventoryItemLink("player", show)) then
     						show = GetInventoryItemLink("player", show)
     					end
					self.macroshow = show
				end
			else
				self.macroshow = nil
			end
		end
	end
end

local function setSpellIcon(self, spell)

	local texture

	if (self.config.macroIcon == 1) then

		spell = lower(spell)

		if (spellIndex[spell]) then

			texture = GetSpellTexture(spellIndex[spell][1], spellIndex[spell][4])

		elseif (companionIndex[spell]) then

			texture = companionIndex[spell][6]

		else
			texture = GetSpellTexture(spell)
		end

		if (not texture) then
			GetNumMacroIcons()
			texture = GetMacroIconInfo(1)
		end

		if (texture) then

			local shapeshift = isActiveShapeshiftSpell(spell)

			if (shapeshift) then
				self.iconframeicon:SetTexture(shapeshift)
			else
				self.iconframeicon:SetTexture(texture)
			end

			self.iconframeicon:Show()
		else
			self.iconframeicon:SetTexture("")
			self.iconframeicon:Hide()
		end
	else
		GetNumMacroIcons()
		texture = GetMacroIconInfo(self.config.macroIcon)

		if (texture) then
			self.iconframeicon:SetTexture(texture)
			self.iconframeicon:Show()
		else
			self.iconframeicon:SetTexture("")
			self.iconframeicon:Hide()
		end
	end

	return texture
end

local function setItemIcon(self, item)

	local _,texture, link, itemID

	if (IsEquippedItem(item)) then

		self.border:SetVertexColor(0, 1.0, 0, 0.5)
		self.border:Show()

	else
		self.border:Hide()
	end

	if (self.config.macroIcon == 1) then

		_, link, _, _, _, _, _, _, _, texture = GetItemInfo(item)

		if (link and not itemCache[item]) then

			_, itemID = strsplit(":", link)

			if (itemID) then
				itemCache[item] = itemID
			end
		end

		if (not texture) then

			if (itemCache[item]) then
				texture = GetItemIcon("item:"..itemCache[item]..":0:0:0:0:0:0:0")
			else
				GetNumMacroIcons()
				texture = GetMacroIconInfo(1)
			end
		end

		if (texture) then

			self.iconframeicon:SetTexture(texture)
			self.iconframeicon:Show()
		else

			self.iconframeicon:SetTexture("")
			self.iconframeicon:Hide()
		end
	else

		GetNumMacroIcons()
		texture = GetMacroIconInfo(self.config.macroIcon)

		if (texture) then
			self.iconframeicon:SetTexture(texture)
			self.iconframeicon:Show()
		else
			self.iconframeicon:SetTexture("")
			self.iconframeicon:Hide()
		end
	end


	return texture
end

local function updateMacroIcon(self)

	setupMacroData(self)

	local spell, item, show, rank, texture = self.macrospell, self.macroitem, self.macroshow, self.macrorank

	if (show and show ~= "") then

    		if(GetItemInfo(show) or itemCache[show]) then
			texture = setItemIcon(self, show)
    		else
			texture = setSpellIcon(self, show)
    		end

	elseif (spell and spell ~= "") then

		texture = setSpellIcon(self, spell)

	elseif (item and item ~= "") then

		texture = setItemIcon(self, item)

	else
		if (strlen(self.config.macro) > 0) then

			if (self.macropet and petTokenIcons[self.macropet]) then
				texture = petTokenIcons[self.macropet][1]
			else
				GetNumMacroIcons()
				texture = GetMacroIconInfo(self.config.macroIcon)
			end

			self.iconframeicon:SetTexture(texture or "")
			self.iconframeicon:Show()

		else
			self.iconframeicon:SetTexture("")
			self.iconframeicon:Hide()
			self.border:Hide()
		end
	end

	return texture
end

local function setSpellState(self, spell)

	if (self.config.spellCounts) then

		local amount, powertype = getPowertypeAmount(self)

		if (amount) then

			local count = floor(UnitMana("player")/amount)

			if (count > 0 and powerColors[powertype]) then
				self.count:SetText(count)
				self.count:SetTextColor(powerColors[powertype].r, powerColors[powertype].g, powerColors[powertype].b)
			else
				self.count:SetText("")
			end
		end

	elseif (self.config.comboCounts) then

		local count = GetComboPoints("player", "target")

		if (count > 0) then
			self.count:SetText(count)
			self.count:SetTextColor(powerColors.Rage.r, powerColors.Rage.g, powerColors.Rage.b)
		else
			self.count:SetText("")
		end

	elseif (GetSpellCount(spell) and  GetSpellCount(spell) > 1) then

		self.count:SetText(GetSpellCount(spell))

	else
		self.count:SetText("")
	end

	if (IsCurrentSpell(spell) or IsAutoRepeatSpell(spell) or isActiveShapeshiftSpell(lower(spell))) then
		self:SetChecked(1)
	else
		self:SetChecked(nil)
	end

	if ((IsAttackSpell(spell) and IsCurrentSpell(spell)) or IsAutoRepeatSpell(spell)) then
		self.mac_flash = true
	else
		self.mac_flash = false
	end
end

local function setItemState(self, item)

	if (chargeTable[item]) then
		self.count:SetText(GetItemCharge(self, item))
	elseif (GetItemCount(item) and  GetItemCount(item) > 1) then
		self.count:SetText(GetItemCount(item))
	else
		self.count:SetText("")
	end

	if(IsCurrentItem(item)) then
		self:SetChecked(1)
	else
		self:SetChecked(nil)
	end
end

local function updateMacroState(self)

	self.updateQueue = nil

	if (chargeUpdate and playerEnteredWorld) then
		self.updateQueue = true
		return
	end

	local spell, item, show = self.macrospell, self.macroitem, self.macroshow

	self.name:SetText(self.config.macroName)

	if (show and show ~= "") then

    		if(GetItemInfo(show) or itemCache[show]) then
			setItemState(self, show)
    		else
			setSpellState(self, show)
    		end

	elseif (spell and spell ~= "") then

		setSpellState(self, spell)

	elseif (item and item ~= "") then

		setItemState(self, item)

	else
		if (self.macropet and petTokenIcons[self.macropet]) then

		else
			self:SetChecked(nil)
		end

		self.count:SetText("")
	end
end

local function setSpellCooldown(self, spell)

	local start, duration, enable

	spell = lower(spell)

	if (companionIndex[spell]) then

		local companion, index = companionIndex[spell][1], companionIndex[spell][2]
		start, duration, enable = GetCompanionCooldown(companion, index)
	else

		start, duration, enable = GetSpellCooldown(spell)
	end

	if (enable) then

		if (self.cdcolor1 and duration > 4) then
			self.cooldowntext1:SetTextColor(self.cdcolor1[1], self.cdcolor1[2], self.cdcolor1[3])
			self.cooldowntext2:SetTextColor(self.cdcolor2[1], self.cdcolor2[2], self.cdcolor2[3])
		end

		if (enable > 0) then
			CooldownFrame_SetTimer(self.iconframecooldown, start, duration, enable)
			self.cooldown = true;
			self.cdduration = duration
		else
			CooldownFrame_SetTimer(self.iconframecooldown, 0, 0, 0)
			self.cooldowntext1:SetText("")
			self.cooldowntext2:SetText("")
		end
	end
end

local function setItemCooldown(self, item)

	local start, duration, enable = GetItemCooldown(item)

	if (enable) then

		if (self.cdcolor1 and duration > 4) then
			self.cooldowntext1:SetTextColor(self.cdcolor1[1], self.cdcolor1[2], self.cdcolor1[3])
			self.cooldowntext2:SetTextColor(self.cdcolor2[1], self.cdcolor2[2], self.cdcolor2[3])
		end

		if (enable > 0) then

			CooldownFrame_SetTimer(self.iconframecooldown, start, duration, enable)
			self.cooldown = true;
			self.cdduration = duration
		else

			CooldownFrame_SetTimer(self.iconframecooldown, 0, 0, 0)
			self.cooldowntext1:SetText("")
			self.cooldowntext2:SetText("")
		end
	end
end

local function updateMacroCooldown_OnEvent(self, update)

	self.cdduration = 0

	local spell, item, show = self.macrospell, self.macroitem, self.macroshow

	if (show and show ~= "") then

    		if(GetItemInfo(show) or itemCache[show]) then
			setItemCooldown(self, show)
    		else
			setSpellCooldown(self, show)
    		end

	elseif (spell and spell ~= "") then

		setSpellCooldown(self, spell)

	elseif (item and item ~= "") then

		setItemCooldown(self, item)

	elseif (update) then

		CooldownFrame_SetTimer(self.iconframecooldown, 0, 0, 0)
		self.cooldowntext1:SetText("")
		self.cooldowntext2:SetText("")
	end
end

local function updateSpellCooldown(self, spell)

	local start, duration, enable = 0, 0, 0

	spell = lower(spell)

	self.spelldata = spellIndex[spell]

	if (companionIndex[spell]) then
		local companion, index = companionIndex[spell][1], companionIndex[spell][2]
		start, duration, enable = GetCompanionCooldown(companion, index)
	else
		start, duration, enable = GetSpellCooldown(spell)
	end

	if (start == 0) then
		self.cooldown = nil
	end

	if (self.alpha and duration) then
		if (self.cooldown and duration > 4) then
			if (self:GetAlpha() ~= ss.cooldownAlpha) then
				self:SetAlpha(ss.cooldownAlpha)
			end
		else
			if (self:GetAlpha() ~= 1) then
				self:SetAlpha(1)
			end
		end
	end

	if (ss.checkButtons[113]) then
		updateCooldownText(self, start or 0, duration or 0, enable or 0)
	elseif (not self.buffup) then
		updateCooldownText(self, 0, 0, 0)
	elseif (not ss.checkButtons[114]) then
		updateCooldownText(self, 0, 0, 0)
	end
end

local function updateItemCooldown(self, item)

	local start, duration, enable = GetItemCooldown(item)

	if (start == 0) then
		self.cooldown = nil
	end

	if (self.alpha and duration) then
		if (self.cooldown and duration > 4) then
			if (self:GetAlpha() ~= ss.cooldownAlpha) then
				self:SetAlpha(ss.cooldownAlpha)
			end
		else
			if (self:GetAlpha() ~= 1) then
				self:SetAlpha(1)
			end
		end
	end

	if (ss.checkButtons[113]) then
		updateCooldownText(self, start or 0, duration or 0, enable or 0)
	elseif (not self.buffup) then
		updateCooldownText(self, 0, 0, 0)
	elseif (not ss.checkButtons[114]) then
		updateCooldownText(self, 0, 0, 0)
	end
end

local function updateMacroCooldown_OnUpdate(self)

	local spell, item, show = self.macrospell, self.macroitem, self.macroshow

	if (show and show ~= "") then

    		if(GetItemInfo(show) or itemCache[show]) then
			updateItemCooldown(self, show)
    		else
			updateSpellCooldown(self, show)
    		end

	elseif (spell and spell ~= "") then

		updateSpellCooldown(self, spell)

	elseif (item and item ~= "") then

		updateItemCooldown(self, item)
	end
end

local function updateSpellUsable(self, spell)

	local isUsable, notEnoughMana = IsUsableSpell(spell)

	if (notEnoughMana) then

		self.iconframeicon:SetVertexColor(self.manacolor[1], self.manacolor[2], self.manacolor[3])

	elseif (isUsable) then

		if (IsSpellInRange(spell, self.target) == 0) then
			self.iconframeicon:SetVertexColor(self.rangecolor[1], self.rangecolor[2], self.rangecolor[3])
		else
			self.iconframeicon:SetVertexColor(1.0, 1.0, 1.0)
		end
	else
		if (spellIndex[lower(spell)]) then

			self.iconframeicon:SetVertexColor(0.4, 0.4, 0.4)
		else
			self.iconframeicon:SetVertexColor(1.0, 1.0, 1.0)
		end
	end

end

local function updateItemUsable(self, item)

       local isUsable, notEnoughMana = IsUsableItem(item)

	if (notEnoughMana) then
		self.iconframeicon:SetVertexColor(self.manacolor[1], self.manacolor[2], self.manacolor[3])
	elseif (isUsable) then
		if (IsItemInRange(spell, self.target) == 0) then
			self.iconframeicon:SetVertexColor(self.rangecolor[1], self.rangecolor[2], self.rangecolor[3])
		else
			self.iconframeicon:SetVertexColor(1.0, 1.0, 1.0)
		end
	else
		self.iconframeicon:SetVertexColor(0.4, 0.4, 0.4)
	end
end

local function updateMacroButton(self)

	local spell, item, show = self.macrospell, self.macroitem, self.macroshow

	if (self.editmode) then

		self.iconframeicon:SetVertexColor(0.2, 0.2, 0.2)

	elseif (show and show ~= "") then

    		if(GetItemInfo(show) or itemCache[show]) then
			updateItemUsable(self, show)
    		else
			updateSpellUsable(self, show)
    		end

	elseif (spell and spell ~= "") then

		updateSpellUsable(self, spell)

	elseif (item and item ~= "") then

		updateItemUsable(self, item)

	else
		self.iconframeicon:SetVertexColor(1.0, 1.0, 1.0)
	end
end

local function setSpellTooltip(self, spell)

	if (spellIndex[spell] and spellIndex[spell][1] and spellIndex[spell][4]) then

		GameTooltip:SetSpell(spellIndex[spell][1], spellIndex[spell][4])

		self.UpdateTooltip = macroButton_SetTooltip

	elseif (companionIndex[spell]) then

		GameTooltip:SetHyperlink("spell:"..companionIndex[spell][5])

		self.UpdateTooltip = nil

	end
end

local function setItemTooltip(self, item)

	local _, link = GetItemInfo(item)

	if (link) then

		GameTooltip:SetHyperlink(link)

	elseif (itemCache[item]) then

		GameTooltip:SetHyperlink("item:"..itemCache[item]..":0:0:0:0:0:0:0")
	end
end

local function macroButton_SetTooltip(self)

	self.UpdateTooltip = nil

	if (self.config.macroUseNote) then

		GameTooltip:SetText(self.config.macroNote)

	else

		local spell, item, show = self.macrospell, self.macroitem, self.macroshow

		if (show and show ~= "") then

			if(GetItemInfo(show) or itemCache[show]) then
				setItemTooltip(self, show)
			else
				setSpellTooltip(self, lower(show))
				self.UpdateTooltip = macroButton_SetTooltip
			end

		elseif (spell and spell ~= "") then

			setSpellTooltip(self, lower(spell))

		elseif (item and item ~= "") then

			setItemTooltip(self, item)

		else
			if (self.macropet and petTokenIcons[self.macropet]) then
				GameTooltip:SetText(petTokenIcons[self.macropet][2], 1, 1, 1)
			else
				GameTooltip:SetText(self.config.macroName)
			end
		end
	end
end

local function updateMacro_OnEvent(self)

	updateMacroIcon(self)
	updateMacroState(self)
	updateBuffup_OnEvent(self, "player", self.macrospell)
	updateBuffup_OnEvent(self, "target", self.macrospell)

	if (self.macrospell or self.macroitem or self.macroshow or strlen(self.config.macro) > 0) then

		self.normaltexture:SetTexture(self.hasAction or "")
		self.normaltexture:SetVertexColor(1,1,1,1)

	else

		if (strlen(self.config.macro) > 0) then
			self.normaltexture:SetVertexColor(1,1,1,1)
		else
			self.normaltexture:SetVertexColor(1,1,1,0.35)

		end

		self.normaltexture:SetTexture(self.noAction or "")
	end
end

local function macroButton_OnUpdate(self, elapsed)

	self.elapsed = self.elapsed + elapsed

	if (self.mac_flash) then

		self.mac_flashing = true

		if (alphaDir == 1) then
			if ((1-(alphaTimer)) >= 0) then
				self.checkedtexture:SetVertexColor(1, 1, 1, 1)
			end
		elseif (alphaDir == 0) then
			if ((alphaTimer) <= 1) then
				self.checkedtexture:SetVertexColor(0.8, 0, 0, 1)
			end
		end

	elseif (self.mac_flashing) then

		self.checkedtexture:SetVertexColor(1, 1, 1, 1)
		self.mac_flashing = false
	end

	if (self.elapsed > 0.2) then

		updateMacroButton(self)

		if (self.cooldown) then
			updateMacroCooldown_OnUpdate(self)
		end

		if (self.buffup and self.buffupunit) then
			updateBuffup_OnUpdate(self, self.buffupunit, self.macrospell)
		end

		self.elapsed = 0;
	end

	if (self.updateQueue) then
		updateMacroState(self)
	end
end

local function macroButton_ShowGrid(button)

	if (not InCombatLockdown()) then

		if (button:GetAttribute("stateshown")) then
			button:Show()
		end
	end

	updateMacroState(button)
end

local function macroButton_HideGrid(button)

	if (not InCombatLockdown()) then

		if (not button.config.stored and not button:GetAttribute("editmode")) then
			if (not hasAction(button ,button.config.macro) and not button.showGrid) then
				button:Hide()
			end
		end
	end

	updateMacroState(button)
end

local function macroButton_OnEvent(self, event, ...)

	local unit, spell = ...

	if (event == "ACTIONBAR_UPDATE_COOLDOWN") then

		updateMacroState(self)
		updateMacroCooldown_OnEvent(self, true)

	elseif (event == "ACTIONBAR_UPDATE_STATE" or
		event == "BAG_UPDATE_COOLDOWN" or
	        event == "CRAFT_SHOW" or
	        event == "CRAFT_CLOSE" or
	        event == "TRADE_SKILL_SHOW" or
	        event == "TRADE_SKILL_CLOSE" or
	        event == "SPELL_UPDATE_USABLE") then

	        if (self.updateicon) then
			updateMacroIcon(self); self.updateicon = nil
		end

		updateMacroState(self)

	elseif (event == "BAG_UPDATE") then

		updateMacroState(self)

	elseif (event == "ITEM_LOCK_CHANGED") then

		if (not chargeUpdate) then

			if (GetCursorInfo()) then
				macroButton_ShowGrid(self)
			else
				macroButton_HideGrid(self)
			end

		end

		updateMacroState(self)

	elseif (event == "ACTIONBAR_SHOWGRID") then

		if (not chargeUpdate) then
			macroButton_ShowGrid(self); self.hidegrid = true
		end

	elseif (event == "ACTIONBAR_HIDEGRID") then

		if (not chargeUpdate or self.hidegrid) then
			macroButton_HideGrid(self); self.hidegrid = nil
		end

	elseif (event == "UPDATE_SHAPESHIFT_FORM") then

		updateMacroIcon(self)

	elseif (self.macrospell and event == "UNIT_AURA" and (unit == "player" or unit == "target")) then

		updateMacroIcon(self)
		updateMacroState(self)
		updateBuffup_OnEvent(self, ..., self.macrospell)

	elseif (unit == "player" and event == "UNIT_INVENTORY_CHANGED") then

		updateMacroState(self)
		updateMacroIcon(self)

	elseif (self.config.spellCounts and unit == "player" and (event == "UNIT_MANA" or event == "UNIT_RAGE" or event == "UNIT_ENERGY" or event == "UNIT_RUNIC_POWER")) then

		updateMacroState(self)

	elseif (self.config.comboCounts and unit == "player" and event == "UNIT_COMBO_POINTS") then

		updateMacroState(self)

	elseif ((unit == "player" or unit == "pet") and
		(event == "UNIT_SPELLCAST_SUCCEEDED" or
		event == "UNIT_SPELLCAST_INTERRUPTED" or
	        event == "UNIT_SPELLCAST_FAILED" or
	        event == "UNIT_SPELLCAST_FAILED_QUIET" or
	        event == "UNIT_SPELLCAST_STOP")) then

		if (self.castrandom and event == "UNIT_SPELLCAST_SUCCEEDED") then

			if (find(self.castrandom, spell)) then

				self.macrospell = spell
				self.config.macroRand = spell

				if (not InCombatLockdown()) then
					Macaroon.SetButtonType(self)
				end
			end
		end

		if (self.macrospell) then

			if (lower(spell) == lower(match(self.macrospell, "^[^(]+"))) then
				self.updateicon = true
			end

			updateMacro_OnEvent(self)
			updateMacroCooldown_OnEvent(self, true)
		end

	elseif (event == "PLAYER_TARGET_CHANGED") then

		updateMacro_OnEvent(self)
		updateMacroCooldown_OnEvent(self, true)

	elseif (event == "PLAYER_FOCUS_CHANGED" or
		event == "PLAYER_REGEN_ENABLED" or
		event == "PLAYER_REGEN_DISABLED" or
		event == "MODIFIER_STATE_CHANGED" or
		event == "ACTIONBAR_PAGE_CHANGED") then

		updateMacro_OnEvent(self)
		updateMacroCooldown_OnEvent(self, true)

	elseif (event == "PLAYER_ENTERING_WORLD") then

		if (self.castrandom and self.config.macroRand) then
			if (find(self.castrandom, self.config.macroRand)) then
				self.macrospell = self.config.macroRand
			end
		end

		updateMacro_OnEvent(self)
		updateMacroCooldown_OnEvent(self)

	elseif (self.macrospell and self.macrospell ~= "" and (event == "PLAYER_ENTER_COMBAT" or event == "PLAYER_LEAVE_COMBAT")) then

		if (IsAttackSpell(self.macrospell)) then
			updateMacroState(self)
		end

	elseif (self.macrospell and self.macrospell ~= "" and event == "START_AUTOREPEAT_SPELL" ) then

		if (IsAutoRepeatSpell(self.macrospell)) then
			updateMacroState(self)
		end

	elseif (self.macrospell and self.macrospell ~= "" and event == "STOP_AUTOREPEAT_SPELL" ) then

		if (self.mac_flashing and not IsAttackSpell(self.macrospell)) then
			updateMacroState(self)
		end
	end

	self.elapsed = 0.2
end

local function updateButton(button)

	if (button.config.type == "action") then

		updateAction_OnEvent(button, button.config.action)
		updateActionCooldown_OnEvent(button, true, button.config.action)

	elseif (button.config.type == "macro") then

		setupMacroData(button)
		macroButton_OnEvent(button, "PLAYER_ENTERING_WORLD")
		updateMacroCooldown_OnEvent(button, true)

	elseif (button.config.type == "pet") then

		updatePet_OnEvent(button, button.config.action)
		updatePetCooldown_OnEvent(button, button.config.action)
		if (not InCombatLockdown()) then
			button:SetAttribute("*macrotext2", "/petautocasttoggle "..button.config.spell)
		end
	end
end

--[[ local button script handlers ]]--

local function button_OnShow(self)

	self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN")
	self:RegisterEvent("ACTIONBAR_UPDATE_STATE")
	self:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
	self:RegisterEvent("ACTIONBAR_PAGE_CHANGED")

	self:RegisterEvent("START_AUTOREPEAT_SPELL")
	self:RegisterEvent("STOP_AUTOREPEAT_SPELL")

	self:RegisterEvent("CRAFT_SHOW")
	self:RegisterEvent("CRAFT_CLOSE")
	self:RegisterEvent("TRADE_SKILL_SHOW")
	self:RegisterEvent("TRADE_SKILL_CLOSE")

	self:RegisterEvent("UPDATE_SHAPESHIFT_FORM")

	self:RegisterEvent("MODIFIER_STATE_CHANGED")

	self:RegisterEvent("UNIT_SPELLCAST_STOP")
	self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
	self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
	self:RegisterEvent("UNIT_SPELLCAST_FAILED")
	self:RegisterEvent("UNIT_SPELLCAST_FAILED_QUIET")
	self:RegisterEvent("UNIT_PET")
	self:RegisterEvent("UNIT_AURA")
	self:RegisterEvent("UNIT_FLAGS")
	self:RegisterEvent("UNIT_MANA")
	self:RegisterEvent("UNIT_RAGE")
	self:RegisterEvent("UNIT_ENERGY")
	self:RegisterEvent("UNIT_RUNIC_POWER")
	self:RegisterEvent("UNIT_COMBO_POINTS")

	self:RegisterEvent("PLAYER_TARGET_CHANGED")
	self:RegisterEvent("PLAYER_FOCUS_CHANGED")
	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("PLAYER_REGEN_DISABLED")
	self:RegisterEvent("PLAYER_ENTER_COMBAT")
	self:RegisterEvent("PLAYER_LEAVE_COMBAT")
	self:RegisterEvent("PLAYER_CONTROL_LOST")
	self:RegisterEvent("PLAYER_CONTROL_GAINED")
	self:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED")

	self:RegisterEvent("UNIT_INVENTORY_CHANGED")
	self:RegisterEvent("BAG_UPDATE_COOLDOWN")
	self:RegisterEvent("BAG_UPDATE")

	self:RegisterEvent("PET_BAR_UPDATE")
	self:RegisterEvent("PET_BAR_UPDATE_COOLDOWN")

	self:RegisterEvent("SPELL_UPDATE_USABLE")

	if (self.config) then

		updateButton(self)

		if (self.config.type == "action") then

			updateBuffup_OnEvent(self, "player", self.config.spell)
			updateBuffup_OnEvent(self, "target", self.config.spell)

		elseif (self.config.type == "macro") then

			updateBuffup_OnEvent(self, "player", self.macrospell)
			updateBuffup_OnEvent(self, "target", self.macrospell)
		end
	end
end

local function button_OnHide(self)

	self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN")
	self:UnregisterEvent("ACTIONBAR_UPDATE_STATE")
	self:UnregisterEvent("ACTIONBAR_SLOT_CHANGED")
	self:UnregisterEvent("ACTIONBAR_PAGE_CHANGED")

	self:UnregisterEvent("START_AUTOREPEAT_SPELL")
	self:UnregisterEvent("STOP_AUTOREPEAT_SPELL")

	self:UnregisterEvent("CRAFT_SHOW")
	self:UnregisterEvent("CRAFT_CLOSE")
	self:UnregisterEvent("TRADE_SKILL_SHOW")
	self:UnregisterEvent("TRADE_SKILL_CLOSE")

	self:UnregisterEvent("UPDATE_SHAPESHIFT_FORM")

	self:UnregisterEvent("MODIFIER_STATE_CHANGED")

	self:UnregisterEvent("UNIT_SPELLCAST_STOP")
	self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED")
	self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED")
	self:UnregisterEvent("UNIT_SPELLCAST_FAILED")
	self:UnregisterEvent("UNIT_SPELLCAST_FAILED_QUIET")
	self:UnregisterEvent("UNIT_PET")
	self:UnregisterEvent("UNIT_FLAGS")
	self:UnregisterEvent("UNIT_AURA")
	self:UnregisterEvent("UNIT_MANA")
	self:UnregisterEvent("UNIT_RAGE")
	self:UnregisterEvent("UNIT_ENERGY")
	self:UnregisterEvent("UNIT_RUNIC_POWER")
	self:UnregisterEvent("UNIT_COMBO_POINTS")

	self:UnregisterEvent("PLAYER_TARGET_CHANGED")
	self:UnregisterEvent("PLAYER_FOCUS_CHANGED")
	self:UnregisterEvent("PLAYER_REGEN_ENABLED")
	self:UnregisterEvent("PLAYER_REGEN_DISABLED")
	self:UnregisterEvent("PLAYER_ENTER_COMBAT")
	self:UnregisterEvent("PLAYER_LEAVE_COMBAT")
	self:UnregisterEvent("PLAYER_CONTROL_LOST")
	self:UnregisterEvent("PLAYER_CONTROL_GAINED")
	self:UnregisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED")

	self:UnregisterEvent("UNIT_INVENTORY_CHANGED")
	self:UnregisterEvent("BAG_UPDATE_COOLDOWN")
	self:UnregisterEvent("BAG_UPDATE")

	self:UnregisterEvent("PET_BAR_UPDATE")
	self:UnregisterEvent("PET_BAR_UPDATE_COOLDOWN")

	self:UnregisterEvent("SPELL_UPDATE_USABLE")

end

local function button_ShowGrid(edit)

	for k,v in pairs(Macaroon.Buttons) do

		if (edit) then
			v[1]:SetAttribute("editmode", true)
		end

		if (v[1].config.type == "action") then
			actionButton_OnEvent(v[1], "ACTIONBAR_SHOWGRID")
		elseif (v[1].config.type == "macro") then
			macroButton_OnEvent(v[1], "ACTIONBAR_SHOWGRID")
		elseif (v[1].config.type == "pet") then
			petButton_OnEvent(v[1], "PET_BAR_SHOWGRID")
		end
	end
end

tinsert(Macaroon.ShowGrids, button_ShowGrid)

local function button_HideGrid(edit)

	for k,v in pairs(Macaroon.Buttons) do

		if (edit) then
			v[1]:SetAttribute("editmode", false)
		end

		if (v[1].config.type == "action") then
			actionButton_OnEvent(v[1], "ACTIONBAR_HIDEGRID")
		elseif (v[1].config.type == "macro") then
			macroButton_OnEvent(v[1], "ACTIONBAR_HIDEGRID")
		elseif (v[1].config.type == "pet") then
			petButton_OnEvent(v[1], "PET_BAR_HIDEGRID")
		end
	end

	Macaroon.AddonSupport("DrDamage")

end

tinsert(Macaroon.HideGrids, button_HideGrid)

local function placeMacro(self, pickup)

	self.config.macro = macroDrag[2]
	self.config.macroIcon = macroDrag[3]
	self.config.macroName = macroDrag[4]
	self.config.macroNote = macroDrag[5]
	self.config.macroUseNote = macroDrag[6]
	self.config.macroAuto = macroDrag[8]
	self.config.macroRand = macroDrag[9]

	if (not self.cursor) then

		Macaroon.SetButtonType(self)

		updateButton(self)

		if (macroDrag[1] ~= self) then

			if (macroDrag[1].dragbutton == "RightButton" and ss.checkButtons[107]) then

			else
				macroDrag[1].config.macro = ""
				macroDrag[1].config.macroIcon = 1
				macroDrag[1].config.macroName = ""
				macroDrag[1].config.macroNote = ""
				macroDrag[1].config.macroUseNote = false
				macroDrag[1].config.macroAuto = false
				macroDrag[1].config.macroRand = false
				macroDrag[1].macrospell = nil
				macroDrag[1].macroitem = nil
				macroDrag[1].macroshow = nil
			end

			Macaroon.SetButtonType(macroDrag[1])

			onEvent = macroDrag[1]:GetScript("OnEvent")
			onEvent(macroDrag[1], "PLAYER_ENTERING_WORLD")
		end
	end

	macroDrag = nil

	if (not pickup) then
		ClearCursor(); SetCursor(nil)
	end

	button_HideGrid()
end

local function pickupMacro(self, currmacro)

	if (currmacro) then

		button_ShowGrid()

		macroDrag = { currmacro[1], currmacro[2], currmacro[3], currmacro[4], currmacro[5], currmacro[6], currmacro[7], currmacro[8] }

		SetCursor(currmacro[7])

		return true

	elseif (hasAction(self ,self.config.macro)) then

		button_ShowGrid()

		macroDrag = { self, self.config.macro, self.config.macroIcon, self.config.macroName, self.config.macroNote, self.config.macroUseNote, updateMacroIcon(self), self.config.macroAuto, self.config.macroRand }

		if (self.dragbutton == "RightButton" and ss.checkButtons[107]) then

		else
			self.config.macro = ""
			self.config.macroIcon = 1
			self.config.macroName = ""
			self.config.macroNote = ""
			self.config.macroUseNote = false
			self.config.macroAuto = false
			self.config.macroRand = false
			self.macrospell = nil
			self.macrorank = nil
			self.macroitem = nil
			self.macroshow = nil
		end

		Macaroon.SetButtonType(self)

		SetCursor(macroDrag[7])

		return true
	else

		return false

	end
end

local function placeCompanion(self)

	if (not companionDrag) then

		--local cursorType, action1, action2 = GetCursorInfo()

		--print(cursorType)
		--print(action1)
		--print(action2)

		return
	end


	if (companionDrag[4]) then
		self.config.macro = "/cast "..companionDrag[4].."()"
	else
		self.config.macro = ""
	end

	self.config.macroIcon = 1
	self.config.macroName = ""
	self.config.macroNote = ""
	self.config.macroUseNote = false
	self.config.macroAuto = false
	self.config.macroRand = false

	if (not self.cursor) then

		Macaroon.SetButtonType(self)

		updateButton(self)
	end

	companionDrag = nil

	ClearCursor(); SetCursor(nil)

	button_HideGrid()
end

local function placeSpell(self, action1, action2, hasmacro)

	local modifier, spell, rank, texture = " "

	if (action1 == 0) then
		return
	else

	 	spell, rank = GetSpellName(action1, action2)

	 	self.config.macro = autoWriteMacro(self, spell, rank)
	 	self.config.macroAuto = spell..";"..rank
	 	self.config.macroIcon = 1

	end

	self.config.macroName = ""
	self.config.macroNote = ""
	self.config.macroUseNote = false
	self.config.macroRand = false

	if (not self.cursor) then

		Macaroon.SetButtonType(self)

		updateButton(self)
	end

	macroDrag = nil

	ClearCursor(); SetCursor(nil)

	button_HideGrid()
end

local function placeItem(self, action1, action2, hasmacro)

	local item, link = GetItemInfo(action2)

	if ( GetItemSpell(item) ) then
		self.config.macro = "/use "..item
	else
		self.config.macro = "/equip "..item
	end

	self.config.macroIcon = 1
	self.config.macroName = ""
	self.config.macroNote = ""
	self.config.macroUseNote = false
	self.config.macroAuto = false
	self.config.macroRand = false

	if (not self.cursor) then

		Macaroon.SetButtonType(self)

		updateButton(self)
	end

	macroDrag = nil

	ClearCursor(); SetCursor(nil)

	button_HideGrid()
end

local function placeBlizzMacro(self, action1, hasmacro)

	local name, icon, body = GetMacroInfo(action1)

	self.config.macro = body
	self.config.macroIcon = Macaroon.macroIconIndex[icon] or 1
	self.config.macroName = name
	self.config.macroNote = ""
	self.config.macroUseNote = false
	self.config.macroAuto = false
	self.config.macroRand = false

	if (not self.cursor) then

		Macaroon.SetButtonType(self)

		updateButton(self)
	end

	macroDrag = nil

	ClearCursor(); SetCursor(nil)

	button_HideGrid()
end

local function placeBlizzAction(self)

	self.config.type = "action"

	if (self.config.action == 0) then

		self.config.action = self.id

		if (self.config.action > Macaroon.maxActionID) then
			while (self.config.action > Macaroon.maxActionID) do
				self.config.action = self.config.action - Macaroon.maxActionID
			end
		end
	end

	Macaroon.SetButtonType(self, true)

	PlaceAction(self.config.action)

	ClearCursor(); SetCursor(nil)

	if (not self.cursor) then
		Macaroon.SetButtonType(self)
	end

	companionDrag = nil

	updateAction_OnEvent(self, self.config.action)

	actionButton_SetTooltip(self)
end

local function pickUpButton(self, currmacro)

	local pickup

	if (not ss.checkButtons[109]) then
		pickup = true
	elseif (ss.checkButtons[110] and IsShiftKeyDown()) then
		pickup = true
	elseif (ss.checkButtons[111] and IsControlKeyDown()) then
		pickup = true
	elseif (ss.checkButtons[112] and IsAltKeyDown()) then
		pickup = true
	end

	if (pickup or currmacro) then

		if (self.config.type == "action") then

			if (currmacro) then

				pickupMacro(self, currmacro)

			else

				if (self.config.action == 0) then

					self.config.action = self.id

					if (self.config.action > Macaroon.maxActionID) then
						while (self.config.action > Macaroon.maxActionID) do
							self.config.action = self.config.action - Macaroon.maxActionID
						end
					end

					Macaroon.SetButtonType(self)
				end

				PickupAction(self.config.action)

			end

		elseif (self.config.type == "macro") then

			pickupMacro(self, currmacro)

		elseif (self.config.type == "pet") then

			if (currmacro) then

				pickupMacro(self, currmacro)
			else

				if (self.config.action == 0) then

					if (self.id > 10) then
						self.config.action = 10
					else
						self.config.action = self.id
					end

					Macaroon.SetButtonType(self)
				end

				PickupPetAction(self.config.action)
			end
		end

		updateButton(self)
	end
end

function Macaroon.CreateButton(index)

	local button = createButton(index)

	return button

end

function Macaroon.AddButton(command, bar, state)

	local count, currBar, currState, button, newButton = tonumber(command)

	if (bar) then
		currBar = bar
	else
		currBar = Macaroon.CurrentBar
	end

	if (not currBar) then
		MacaroonMessageFrame:AddMessage(MACAROON_STRINGS.NO_BAR_SELECTED, 1.0, 1.0, 1.0, 1.0, UIERRORS_HOLD_TIME)
		return
	end

	if (currBar.config.stored) then
		return
	end

	if (state) then
		currState = state
	else
		currState = currBar.handler:GetAttribute("state-current") or "homestate"
	end

	if (not count or count < 1) then
		count = 1
	end

	for i=1,count do

		newButton = 0

		if (currBar.reverse) then

			for k,v in pairs(currBar.btnTable) do
				if (v[2] == 1 and newButton == 0) then
					newButton = k
				end
				if (v[2] == 1 and k > newButton) then
					newButton = k
				end
			end
		else

			for k,v in pairs(currBar.btnTable) do
				if (v[2] == 1 and newButton == 0) then
					newButton = k
					break
				end
			end
		end



		if (newButton ~= 0) then

			button = _G[currBar.btnType..newButton]
			button.bar = currBar
			button.config.bar = currBar:GetID()
			button.config.stored = false
			button.config.showstates = currState
			button:SetAttribute("showstates", currState)
			button:SetAttribute("editmode", true)

			Macaroon.UpdateButtonVisibility(button, currState)

			if (not currBar.config.buttonList[currState] or currBar.config.buttonList[currState] == "") then
				currBar.config.buttonList[currState] = tostring(button.id)
			elseif (currBar.reverse) then
				currBar.config.buttonList[currState] = button.id..";"..currBar.config.buttonList[currState]
			else
				currBar.config.buttonList[currState] = currBar.config.buttonList[currState]..";"..button.id
			end

			currBar.buttonCountChanged = true

			currBar.btnTable[button.id][2] = 0

		elseif (currBar.btnNew) then

			button = currBar.btnNew(currBar)

			if (button) then

				button.config.bar = currBar:GetID()
				button.config.stored = false
				button.config.showstates = currState
				button:SetAttribute("showstates", currState)
				button:SetAttribute("editmode", true)

				Macaroon.UpdateButtonVisibility(button, currState)

				button.bar = currBar

				if (not currBar.config.buttonList[currState] or currBar.config.buttonList[currState] == "") then
					currBar.config.buttonList[currState] = tostring(button.id)
				else
					currBar.config.buttonList[currState] = currBar.config.buttonList[currState]..";"..button.id
				end

				currBar.buttonCountChanged = true

				currBar.btnTable[button.id][2] = 0
			end
		end
	end

	currBar.updateBar(currBar, nil, true, true)

	for state, btnIDs in pairs(currBar.config.buttonList) do

		for btnID in gmatch(btnIDs, "[^;]+") do

			local set

			button = _G[currBar.btnType..btnID]

			if (currBar.config.pet and state == "homestate") then

				button.config.type = "pet"
				button.config.action = button.config.barPos
				set = true

			elseif (currBar.config.possess and state == "possess1") then

				button.config.type = "action"
				button.config.action = button.config.barPos + 120
				set = true
			end

			if (set) then
				Macaroon.SetButtonType(button)
			end
		end
	end
end

function Macaroon.StoreButton(button, btnTable)

	button:ClearAllPoints()

	button.config.bar = 0
	button.config.barPos = 0
	button.config.scale = 1
	button.config.XOffset = 0
	button.config.YOffset = 0
	button.config.target = "none"
	button.config.stored = true

	button.skinset = false

	button:SetParent("MacaroonButtonStorage")

	if (button.dummy) then
		button.dummy:SetParent("MacaroonButtonStorage")
	end

	btnTable[button.id][2] = 1
end

function Macaroon.RemoveButton(command, bar, state)

	local count, currBar, button, index, currState, btnID = tonumber(command)

	if (not count or count < 1) then
		count = 1
	end

	if (bar) then
		currBar = bar
	else
		currBar = Macaroon.CurrentBar
	end

	if (not currBar) then
		MacaroonMessageFrame:AddMessage(MACAROON_STRINGS.NO_BAR_SELECTED, 1.0, 1.0, 1.0, 1.0, UIERRORS_HOLD_TIME)
		return
	end

	if (state) then
		currState = state
	else
		currState = currBar.handler:GetAttribute("state-current") or "homestate"
	end

	if (currBar.config.buttonList[currState]) then

		for i=1,count do

			if (currBar.reverse) then
				btnID = match(currBar.config.buttonList[currState], "^%d+")
			else
				btnID = match(currBar.config.buttonList[currState], "%d+$")
			end

			if (btnID) then

				button = _G[currBar.btnType..btnID]

				Macaroon.StoreButton(button, currBar.btnTable)

				if (currBar.reverse) then
					currBar.config.buttonList[currState] = gsub(currBar.config.buttonList[currState], "^"..btnID.."[;]*", "")
				else
					currBar.config.buttonList[currState] = gsub(currBar.config.buttonList[currState], "[;]*"..btnID.."$", "")
				end

				currBar.buttonCountChanged = true
			end
		end
	end

	currBar.updateBar(currBar, nil, true, true)
end

function Macaroon.Button_OnLoad(self)

	self.elapsed = 0
	self.id = 0
	self.dir = 0
	self.alphatimer = 0
	self.timedResetcount = 0
	self.cdduration = 0

	self.spells = ""

	self.mac_flash = false
	self.mac_flashing = false
	self.show_tooltip = false
	self.tooltip_shown = false
	self.updateButton = updateButton

	self:RegisterForClicks(ss.registerForClicks)
	self:RegisterForDrag("LeftButton", "RightButton")

	self:RegisterEvent("PLAYER_ENTERING_WORLD")
	self:RegisterEvent("ITEM_LOCK_CHANGED")
	self:RegisterEvent("UPDATE_BONUS_ACTIONBAR")
	self:RegisterEvent("ACTIONBAR_SHOWGRID")
	self:RegisterEvent("ACTIONBAR_HIDEGRID")
	self:RegisterEvent("PET_BAR_SHOWGRID")
	self:RegisterEvent("PET_BAR_HIDEGRID")

	_G[self:GetName().."CooldownText2"]:SetTextColor(1,0,0)
	_G[self:GetName().."HotKey"]:SetTextColor(1,1,1)
	_G[self:GetName().."HotKey"]:SetTextHeight(12)
	_G[self:GetName().."HotKey"]:SetWidth(self:GetWidth())
	_G[self:GetName().."HotKey"]:Hide()

	self:SetFrameLevel(4)
end

local startDrag

function Macaroon.Button_OnDragStart(self, button)

	if (InCombatLockdown()) then
		startDrag = nil
		return
	end

	local drag

	if (not ss.checkButtons[109]) then
		drag = true
	elseif (ss.checkButtons[110] and IsShiftKeyDown()) then
		drag = true
	elseif (ss.checkButtons[111] and IsControlKeyDown()) then
		drag = true
	elseif (ss.checkButtons[112] and IsAltKeyDown()) then
		drag = true
	end

	if (drag) then

		startDrag = true

		self.cooldown = nil
		self.dragbutton = button

		pickUpButton(self)

		if (macroDrag) then
			if (macroDrag[1] ~= self) then
				self.dragbutton = nil
			end
		else
			self.dragbutton = nil
		end
	else
		startDrag = nil
	end
end

function Macaroon.Button_OnDragStop(self)

end

function Macaroon.Button_OnReceiveDrag(self, preclick)

	if (InCombatLockdown()) then
		return
	end

	local cursorType, action1, action2 = GetCursorInfo()

	--print(cursorType)
	--print(action1)
	--print(action2)

	if (self.config.type == "action") then

		if (macroDrag and (macroDrag[1] ~= self or preclick)) then

			self.config.type = "macro"

			if (HasAction(self.config.action)) then
				PickupAction(self.config.action)
				placeMacro(self, true)
			else
				placeMacro(self)
			end
		else

			if (self.config.action == 0) then

				self.config.action = self.id

				if (self.config.action > Macaroon.maxActionID) then
					while (self.config.action > Macaroon.maxActionID) do
						self.config.action = self.config.action - Macaroon.maxActionID
					end
				end

				Macaroon.SetButtonType(self)
			end

			PlaceAction(self.config.action)

			updateAction_OnEvent(self, self.config.action)
		end

		actionButton_SetTooltip(self)

	elseif (self.config.type == "macro") then

		self.currmacro = { self, self.config.macro, self.config.macroIcon, self.config.macroName, self.config.macroNote, self.config.macroUseNote, updateMacroIcon(self), self.config.macroAuto, self.config.macroRand }

		if (companionDrag) then

			placeCompanion(self)

		elseif (action1 == 0) then

			-- do nothing for now

		else

			if (macroDrag) then

				placeMacro(self)

			elseif (cursorType == "spell") then

				placeSpell(self, action1, action2, hasAction(self, self.config.macro))

			elseif (cursorType == "item") then

				placeItem(self, action1, action2, hasAction(self, self.config.macro))

			elseif (cursorType == "macro") then

				placeBlizzAction(self)

				--placeBlizzMacro(self, action1, hasAction(self, self.config.macro))

			end

			macroButton_SetTooltip(self)
		end

		if (self.currmacro[2] and self.currmacro[2] ~= "" and startDrag) then
			pickUpButton(self, self.currmacro)
		end

		clearTable(self.currmacro)

		updateButton(self)

	elseif (self.config.type == "pet") then

		PickupPetAction(self.config.action)
		updateButton(self)
	end

	self.elapsed = 0.2

	startDrag = nil
end

function Macaroon.Button_PreClick(self)

	self.cursor = nil

	local cursorType = GetCursorInfo()

	if (cursorType or macroDrag) then
		self.cursor = true
		startDrag = true
		Macaroon.SetButtonType(self, true)
		Macaroon.Button_OnReceiveDrag(self, true)
	end

end

function Macaroon.Button_PostClick(self)

	if (self.cursor) then
		self.cursor = nil
		Macaroon.SetButtonType(self)
	end

	updateButton(self)
end

function Macaroon.Button_OnEnter(self)

	if (ss.checkButtons[103] and InCombatLockdown()) then
		return
	end

	if (ss.checkButtons[102]) then

		if ( GetCVar("UberTooltips") == "1" ) then
			self.UberTooltips = true
			GameTooltip_SetDefaultAnchor(GameTooltip, self)
		else
			self.UberTooltips = false
			GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
		end

		if (self.config.type == "action") then

			actionButton_SetTooltip(self)

		elseif (self.config.type == "macro") then

			macroButton_SetTooltip(self)

		elseif (self.config.type == "pet") then

			petButton_SetTooltip(self)
		end

		GameTooltip:Show()
	end
end

function Macaroon.Button_OnLeave(self)

	self.UpdateTooltip = nil
	GameTooltip:Hide()
end

local function buttonReset(button)

	button:SetAttribute("unit", nil)
	button:SetAttribute("useparent-unit", nil)
	button:SetAttribute("type", nil)
	button:SetAttribute("type1", nil)
	button:SetAttribute("type2", nil)
	button:SetAttribute("*action*", nil)
	button:SetAttribute("*macrotext*", nil)
	button:SetAttribute("*action1", nil)
	button:SetAttribute("*macrotext2", nil)

end

function Macaroon.SetButtonType(button, kill, initialize)

	if (InCombatLockdown()) then
		return
	end

	buttonReset(button)

	if (kill) then

		button:SetScript("OnEvent", function() end)
		button:SetScript("OnUpdate", function() end)

	else

		button:SetScript("OnShow", button_OnShow)
		button:SetScript("OnHide", button_OnHide)

		if (button.config.type == "action") then

			button:SetAttribute("type", button.config.type)
			button:SetAttribute("*action*", button.config.action)
			button:SetAttribute("useparent-unit", true)
			button:SetScript("OnEvent", actionButton_OnEvent)
			button:SetScript("OnUpdate", actionButton_OnUpdate)

			button.editframetype:SetText(button.config.type.."\nid:"..button.config.action)

			if (initialize) then

				local action = hasAction(button, button.config.action)

				if (action) then
					actionButton_ShowGrid(button)
				else
					actionButton_HideGrid(button)
				end
			end

			if (button.config.action > 120) then
				button:SetAttribute("hasaction", true)
			end

		elseif (button.config.type == "macro") then

			button.macroparse = button.config.macro

			if (button.castrandom and button.config.macroRand) then
				button.macroparse = gsub(button.macroparse, "%s*"..button.config.macroRand.."%s*[,]*", "")
				button.macroparse = gsub(button.macroparse, ",$", "")
			end

			button:SetAttribute("type", button.config.type)
			button:SetAttribute("*macrotext*", button.macroparse)
			button:SetScript("OnEvent", macroButton_OnEvent)
			button:SetScript("OnUpdate", macroButton_OnUpdate)

			if (strlen(button.config.macro) > 0) then
				button.macroparse = "\n"..button.macroparse.."\n"
				button.macroparse = gsub(button.macroparse, "(%c+)", " %1")
			else
				button.macroparse = nil
			end

			button.editframetype:SetText(button.config.type)

			if (initialize) then

				local macro = hasAction(button, button.config.macro)

				if (macro) then
					macroButton_ShowGrid(button)
				else
					macroButton_HideGrid(button)
				end
			end

		elseif (button.config.type == "pet") then

			button:SetAttribute("type1", button.config.type)
			button:SetAttribute("type2", "macro")
			button:SetAttribute("*action1", button.config.action)
			button:SetAttribute("*macrotext2", "/petautocasttoggle "..button.config.spell)
			button:SetAttribute("useparent-unit", false)
			button:SetAttribute("unit", ATTRIBUTE_NOOP)
			button:SetScript("OnEvent", petButton_OnEvent)
			button:SetScript("OnUpdate", petButton_OnUpdate)

			button.editframetype:SetText(button.config.type.."\nid:"..button.config.action)

			if (initialize) then

				local action = hasAction(button, button.config.action)

				if (action) then
					petButton_ShowGrid(button)
				else
					petButton_HideGrid(button)
				end
			end
		end

		updateButton(button)
	end

	for k,v in pairs(Macaroon.StatesToSave) do v() end
end

function Macaroon.UpdateAutoMacros()

	local button, spell, rank

	for k,v in pairs(Macaroon.Buttons) do

		button = v[1]

		if (button.config.macroAuto) then

			spell,rank = (";"):split(button.config.macroAuto)
			button.config.macro = autoWriteMacro(button, spell, rank)
			Macaroon.SetButtonType(button)

		end
	end
end

function Macaroon.UpdateButtonVisibility(button, message)

	if (not message) then return end

	button:SetAttribute("stateshown", false)

	for showstate in gmatch(button:GetAttribute("showstates"), "[^;]+") do

		if (match(message, showstate)) then

			if (button:GetAttribute("hasaction") or
			    button:GetAttribute("showgrid-bar") or
			    button:GetAttribute("editmode")) then
				button:Show()
			end

			button:SetAttribute("stateshown", true)

			for key in gmatch(button:GetAttribute("hotkeys"), "[^:]+") do
				SetOverrideBindingClick(button, false, key, button:GetName())
			end
		end
	end

	if (not button:GetAttribute("stateshown")) then

		button:Hide()

		for key in gmatch(button:GetAttribute("hotkeys"), "[^:]+") do
			SetOverrideBinding(button, true, key, nil)
		end
	end
end

function Macaroon.GetButtonDefaults()

	local defaults = {}

	buttonDefaults(0, defaults)

	return defaults.config
end

function Macaroon.AddNewButton(bar)

	local index, made, button = 1, false

	while not made do

		if (not _G[bar.btnType..index] or (_G[bar.btnType..index] and not _G[bar.btnType..index].config)) then
			button = createButton(index)
			Macaroon.SetButtonType(button)
			made = true
		end

		index = index + 1
	end

	return button
end

local function updateCompanions()

	local button, offset, id, creatureName, _

	if ( PetPaperDollFrameCompanionFrame.mode == "CRITTER" ) then
		offset = (PetPaperDollFrameCompanionFrame.pageCritter or 0)*NUM_COMPANIONS_PER_PAGE
	elseif ( PetPaperDollFrameCompanionFrame.mode == "MOUNT" ) then
		offset = (PetPaperDollFrameCompanionFrame.pageMount or 0)*NUM_COMPANIONS_PER_PAGE
	end

	for i=1,NUM_COMPANIONS_PER_PAGE do
		button = _G["CompanionButton"..i]
		id = i + (offset or 0)
		_, creatureName, _, _, _ = GetCompanionInfo(PetPaperDollFrameCompanionFrame.mode, id)
		button.creatureName = creatureName
	end
end

local function companionCheck()

end

local delete_item

local function buttonsSetSaved()

	if (MacaroonSavedState.useShared and MacaroonSharedSavedState[MacaroonSavedState.sharedProfile]) then

		ss = MacaroonSharedSavedState[MacaroonSavedState.sharedProfile]

		if (not ss) then
			ss = MacaroonSavedState
		end
	else
		ss = MacaroonSavedState
	end
end

local function controlOnEvent(self, event, ...)

	if (event == "VARIABLES_LOADED") then

		buttonsSetSaved()

		itemCache = MacaroonItemCache

		cmdSlash = {
			[SLASH_CAST1] = true,
			[SLASH_CAST2] = true,
			[SLASH_CAST3] = true,
			[SLASH_CAST4] = true,
			[SLASH_CASTRANDOM1] = true,
			[SLASH_CASTRANDOM2] = true,
			[SLASH_CASTSEQUENCE1] = true,
			[SLASH_CASTSEQUENCE2] = true,
			[SLASH_EQUIP1] = true,
			[SLASH_EQUIP2] = true,
			[SLASH_EQUIP3] = true,
			[SLASH_EQUIP4] = true,
			[SLASH_EQUIP_TO_SLOT1] = true,
			[SLASH_EQUIP_TO_SLOT2] = true,
			[SLASH_USE1] = true,
			[SLASH_USE2] = true,
			[SLASH_USERANDOM1] = true,
			[SLASH_USERANDOM2] = true,
			["/cast"] = true,
			["/castrandom"] = true,
			["/castsequence"] = true,
			["/spell"] = true,
			["/equip"] = true,
			["/eq"] = true,
			["/equipslot"] = true,
			["/use"] = true,
			["/userandom"] = true,
		}

	elseif (event == "PLAYER_LOGIN") then

		hooksecurefunc("PetPaperDollFrame_UpdateCompanions", updateCompanions)

		--hack to get info on companions to be able to make them dragable to Macaroon buttons.
		for i=1,NUM_COMPANIONS_PER_PAGE do
			button = _G["CompanionButton"..i]
			button:HookScript("OnDragStart", function(self)
					companionDrag = companionIndex[lower(self.creatureName).."()"]
				end)
		end

		itemChargeScan(self)

	elseif (event == "PLAYER_ENTERING_WORLD") then

		playerEnteredWorld = true

		updateBuffInfo("player")
		updateBuffInfo("target")
		itemChargeScan(self)

	elseif (event == "PLAYER_TARGET_CHANGED") then

		updateBuffInfo("target")

	elseif ( event == "UNIT_AURA" ) then

		if (select(1,...) ==  "player" or select(1,...) ==  "target") then
			updateBuffInfo(...)
		end

	elseif (event == "ACTIONBAR_SHOWGRID") then

		if (not chargeUpdate) then

			local spell, rank = GameTooltip:GetSpell()

			if (spell) then
				spell = lower(spell).."()"
				companionDrag = companionIndex[spell]
			end
		end

		startDrag = true

	elseif (event == "CURSOR_UPDATE") then

		if (macroDrag) then

			if (arg1 == "up") then

				macroDrag = nil

				SetCursor(nil)

				for k,v in pairs(Macaroon.HideGrids) do
					v()
				end
			else
				SetCursor(macroDrag[7])
			end
		end

	elseif (event == "UNIT_INVENTORY_CHANGED") then

		if (select(1,...) ==  "player") then
			MacaroonControl.elapsed = 0; chargeUpdate = true
		end

	elseif (event == "ITEM_LOCK_CHANGED") then

		MacaroonControl.elapsed = 0; chargeUpdate = true

	elseif(event == "BAG_UPDATE") then

		MacaroonControl.elapsed = 0; chargeUpdate = true

	elseif(event == "MODIFIER_STATE_CHANGED") then

		Macaroon.AddonSupport("DrDamage")
	end
end

local frame = CreateFrame("Frame", nil, UIParent)
frame:SetScript("OnEvent", controlOnEvent)
frame:RegisterEvent("VARIABLES_LOADED")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("PLAYER_TARGET_CHANGED")
frame:RegisterEvent("UNIT_AURA")
frame:RegisterEvent("CURSOR_UPDATE")
frame:RegisterEvent("UNIT_INVENTORY_CHANGED")
frame:RegisterEvent("ITEM_LOCK_CHANGED")
frame:RegisterEvent("DELETE_ITEM_CONFIRM")
frame:RegisterEvent("BAG_UPDATE")
frame:RegisterEvent("ACTIONBAR_SHOWGRID")
frame:RegisterEvent("MODIFIER_STATE_CHANGED")